// File generated from our OpenAPI spec
package com.stripe.param;

import com.google.gson.annotations.SerializedName;
import com.stripe.net.ApiRequestParams;
import com.stripe.param.common.EmptyParam;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.EqualsAndHashCode;
import lombok.Getter;

@Getter
@EqualsAndHashCode(callSuper = false)
public class PlanCreateParams extends ApiRequestParams {
  /** Whether the plan is currently available for new subscriptions. Defaults to {@code true}. */
  @SerializedName("active")
  Boolean active;

  /**
   * A positive integer in cents (or local equivalent) (or 0 for a free plan) representing how much
   * to charge on a recurring basis.
   */
  @SerializedName("amount")
  Long amount;

  /**
   * Same as {@code amount}, but accepts a decimal value with at most 12 decimal places. Only one of
   * {@code amount} and {@code amount_decimal} can be set.
   */
  @SerializedName("amount_decimal")
  BigDecimal amountDecimal;

  /**
   * Describes how to compute the price per period. Either {@code per_unit} or {@code tiered}.
   * {@code per_unit} indicates that the fixed amount (specified in {@code amount}) will be charged
   * per unit in {@code quantity} (for plans with {@code usage_type=licensed}), or per unit of total
   * usage (for plans with {@code usage_type=metered}). {@code tiered} indicates that the unit
   * pricing will be computed using a tiering strategy as defined using the {@code tiers} and {@code
   * tiers_mode} attributes.
   */
  @SerializedName("billing_scheme")
  BillingScheme billingScheme;

  /**
   * <strong>Required.</strong> Three-letter <a
   * href="https://www.iso.org/iso-4217-currency-codes.html">ISO currency code</a>, in lowercase.
   * Must be a <a href="https://stripe.com/docs/currencies">supported currency</a>.
   */
  @SerializedName("currency")
  String currency;

  /** Specifies which fields in the response should be expanded. */
  @SerializedName("expand")
  List<String> expand;

  /**
   * Map of extra parameters for custom features not available in this client library. The content
   * in this map is not serialized under this field's {@code @SerializedName} value. Instead, each
   * key/value pair is serialized as if the key is a root-level field (serialized) name in this
   * param object. Effectively, this map is flattened to its parent instance.
   */
  @SerializedName(ApiRequestParams.EXTRA_PARAMS_KEY)
  Map<String, Object> extraParams;

  /**
   * An identifier randomly generated by Stripe. Used to identify this plan when subscribing a
   * customer. You can optionally override this ID, but the ID must be unique across all plans in
   * your Stripe account. You can, however, use the same plan ID in both live and test modes.
   */
  @SerializedName("id")
  String id;

  /**
   * <strong>Required.</strong> Specifies billing frequency. Either {@code day}, {@code week},
   * {@code month} or {@code year}.
   */
  @SerializedName("interval")
  Interval interval;

  /**
   * The number of intervals between subscription billings. For example, {@code interval=month} and
   * {@code interval_count=3} bills every 3 months. Maximum of three years interval allowed (3
   * years, 36 months, or 156 weeks).
   */
  @SerializedName("interval_count")
  Long intervalCount;

  /**
   * Set of <a href="https://stripe.com/docs/api/metadata">key-value pairs</a> that you can attach
   * to an object. This can be useful for storing additional information about the object in a
   * structured format. Individual keys can be unset by posting an empty value to them. All keys can
   * be unset by posting an empty value to {@code metadata}.
   */
  @SerializedName("metadata")
  Object metadata;

  /** The meter tracking the usage of a metered price. */
  @SerializedName("meter")
  String meter;

  /** A brief description of the plan, hidden from customers. */
  @SerializedName("nickname")
  String nickname;

  @SerializedName("product")
  Object product;

  /**
   * Each element represents a pricing tier. This parameter requires {@code billing_scheme} to be
   * set to {@code tiered}. See also the documentation for {@code billing_scheme}.
   */
  @SerializedName("tiers")
  List<PlanCreateParams.Tier> tiers;

  /**
   * Defines if the tiering price should be {@code graduated} or {@code volume} based. In {@code
   * volume}-based tiering, the maximum quantity within a period determines the per unit price, in
   * {@code graduated} tiering pricing can successively change as the quantity grows.
   */
  @SerializedName("tiers_mode")
  TiersMode tiersMode;

  /**
   * Apply a transformation to the reported usage or set quantity before computing the billed price.
   * Cannot be combined with {@code tiers}.
   */
  @SerializedName("transform_usage")
  TransformUsage transformUsage;

  /**
   * Default number of trial days when subscribing a customer to this plan using <a
   * href="https://stripe.com/docs/api#create_subscription-trial_from_plan">{@code
   * trial_from_plan=true}</a>.
   */
  @SerializedName("trial_period_days")
  Long trialPeriodDays;

  /**
   * Configures how the quantity per period should be determined. Can be either {@code metered} or
   * {@code licensed}. {@code licensed} automatically bills the {@code quantity} set when adding it
   * to a subscription. {@code metered} aggregates the total usage based on usage records. Defaults
   * to {@code licensed}.
   */
  @SerializedName("usage_type")
  UsageType usageType;

  private PlanCreateParams(
      Boolean active,
      Long amount,
      BigDecimal amountDecimal,
      BillingScheme billingScheme,
      String currency,
      List<String> expand,
      Map<String, Object> extraParams,
      String id,
      Interval interval,
      Long intervalCount,
      Object metadata,
      String meter,
      String nickname,
      Object product,
      List<PlanCreateParams.Tier> tiers,
      TiersMode tiersMode,
      TransformUsage transformUsage,
      Long trialPeriodDays,
      UsageType usageType) {
    this.active = active;
    this.amount = amount;
    this.amountDecimal = amountDecimal;
    this.billingScheme = billingScheme;
    this.currency = currency;
    this.expand = expand;
    this.extraParams = extraParams;
    this.id = id;
    this.interval = interval;
    this.intervalCount = intervalCount;
    this.metadata = metadata;
    this.meter = meter;
    this.nickname = nickname;
    this.product = product;
    this.tiers = tiers;
    this.tiersMode = tiersMode;
    this.transformUsage = transformUsage;
    this.trialPeriodDays = trialPeriodDays;
    this.usageType = usageType;
  }

  public static Builder builder() {
    return new Builder();
  }

  public static class Builder {
    private Boolean active;

    private Long amount;

    private BigDecimal amountDecimal;

    private BillingScheme billingScheme;

    private String currency;

    private List<String> expand;

    private Map<String, Object> extraParams;

    private String id;

    private Interval interval;

    private Long intervalCount;

    private Object metadata;

    private String meter;

    private String nickname;

    private Object product;

    private List<PlanCreateParams.Tier> tiers;

    private TiersMode tiersMode;

    private TransformUsage transformUsage;

    private Long trialPeriodDays;

    private UsageType usageType;

    /** Finalize and obtain parameter instance from this builder. */
    public PlanCreateParams build() {
      return new PlanCreateParams(
          this.active,
          this.amount,
          this.amountDecimal,
          this.billingScheme,
          this.currency,
          this.expand,
          this.extraParams,
          this.id,
          this.interval,
          this.intervalCount,
          this.metadata,
          this.meter,
          this.nickname,
          this.product,
          this.tiers,
          this.tiersMode,
          this.transformUsage,
          this.trialPeriodDays,
          this.usageType);
    }

    /** Whether the plan is currently available for new subscriptions. Defaults to {@code true}. */
    public Builder setActive(Boolean active) {
      this.active = active;
      return this;
    }

    /**
     * A positive integer in cents (or local equivalent) (or 0 for a free plan) representing how
     * much to charge on a recurring basis.
     */
    public Builder setAmount(Long amount) {
      this.amount = amount;
      return this;
    }

    /**
     * Same as {@code amount}, but accepts a decimal value with at most 12 decimal places. Only one
     * of {@code amount} and {@code amount_decimal} can be set.
     */
    public Builder setAmountDecimal(BigDecimal amountDecimal) {
      this.amountDecimal = amountDecimal;
      return this;
    }

    /**
     * Describes how to compute the price per period. Either {@code per_unit} or {@code tiered}.
     * {@code per_unit} indicates that the fixed amount (specified in {@code amount}) will be
     * charged per unit in {@code quantity} (for plans with {@code usage_type=licensed}), or per
     * unit of total usage (for plans with {@code usage_type=metered}). {@code tiered} indicates
     * that the unit pricing will be computed using a tiering strategy as defined using the {@code
     * tiers} and {@code tiers_mode} attributes.
     */
    public Builder setBillingScheme(PlanCreateParams.BillingScheme billingScheme) {
      this.billingScheme = billingScheme;
      return this;
    }

    /**
     * <strong>Required.</strong> Three-letter <a
     * href="https://www.iso.org/iso-4217-currency-codes.html">ISO currency code</a>, in lowercase.
     * Must be a <a href="https://stripe.com/docs/currencies">supported currency</a>.
     */
    public Builder setCurrency(String currency) {
      this.currency = currency;
      return this;
    }

    /**
     * Add an element to `expand` list. A list is initialized for the first `add/addAll` call, and
     * subsequent calls adds additional elements to the original list. See {@link
     * PlanCreateParams#expand} for the field documentation.
     */
    public Builder addExpand(String element) {
      if (this.expand == null) {
        this.expand = new ArrayList<>();
      }
      this.expand.add(element);
      return this;
    }

    /**
     * Add all elements to `expand` list. A list is initialized for the first `add/addAll` call, and
     * subsequent calls adds additional elements to the original list. See {@link
     * PlanCreateParams#expand} for the field documentation.
     */
    public Builder addAllExpand(List<String> elements) {
      if (this.expand == null) {
        this.expand = new ArrayList<>();
      }
      this.expand.addAll(elements);
      return this;
    }

    /**
     * Add a key/value pair to `extraParams` map. A map is initialized for the first `put/putAll`
     * call, and subsequent calls add additional key/value pairs to the original map. See {@link
     * PlanCreateParams#extraParams} for the field documentation.
     */
    public Builder putExtraParam(String key, Object value) {
      if (this.extraParams == null) {
        this.extraParams = new HashMap<>();
      }
      this.extraParams.put(key, value);
      return this;
    }

    /**
     * Add all map key/value pairs to `extraParams` map. A map is initialized for the first
     * `put/putAll` call, and subsequent calls add additional key/value pairs to the original map.
     * See {@link PlanCreateParams#extraParams} for the field documentation.
     */
    public Builder putAllExtraParam(Map<String, Object> map) {
      if (this.extraParams == null) {
        this.extraParams = new HashMap<>();
      }
      this.extraParams.putAll(map);
      return this;
    }

    /**
     * An identifier randomly generated by Stripe. Used to identify this plan when subscribing a
     * customer. You can optionally override this ID, but the ID must be unique across all plans in
     * your Stripe account. You can, however, use the same plan ID in both live and test modes.
     */
    public Builder setId(String id) {
      this.id = id;
      return this;
    }

    /**
     * <strong>Required.</strong> Specifies billing frequency. Either {@code day}, {@code week},
     * {@code month} or {@code year}.
     */
    public Builder setInterval(PlanCreateParams.Interval interval) {
      this.interval = interval;
      return this;
    }

    /**
     * The number of intervals between subscription billings. For example, {@code interval=month}
     * and {@code interval_count=3} bills every 3 months. Maximum of three years interval allowed (3
     * years, 36 months, or 156 weeks).
     */
    public Builder setIntervalCount(Long intervalCount) {
      this.intervalCount = intervalCount;
      return this;
    }

    /**
     * Add a key/value pair to `metadata` map. A map is initialized for the first `put/putAll` call,
     * and subsequent calls add additional key/value pairs to the original map. See {@link
     * PlanCreateParams#metadata} for the field documentation.
     */
    @SuppressWarnings("unchecked")
    public Builder putMetadata(String key, String value) {
      if (this.metadata == null || this.metadata instanceof EmptyParam) {
        this.metadata = new HashMap<String, String>();
      }
      ((Map<String, String>) this.metadata).put(key, value);
      return this;
    }

    /**
     * Add all map key/value pairs to `metadata` map. A map is initialized for the first
     * `put/putAll` call, and subsequent calls add additional key/value pairs to the original map.
     * See {@link PlanCreateParams#metadata} for the field documentation.
     */
    @SuppressWarnings("unchecked")
    public Builder putAllMetadata(Map<String, String> map) {
      if (this.metadata == null || this.metadata instanceof EmptyParam) {
        this.metadata = new HashMap<String, String>();
      }
      ((Map<String, String>) this.metadata).putAll(map);
      return this;
    }

    /**
     * Set of <a href="https://stripe.com/docs/api/metadata">key-value pairs</a> that you can attach
     * to an object. This can be useful for storing additional information about the object in a
     * structured format. Individual keys can be unset by posting an empty value to them. All keys
     * can be unset by posting an empty value to {@code metadata}.
     */
    public Builder setMetadata(EmptyParam metadata) {
      this.metadata = metadata;
      return this;
    }

    /**
     * Set of <a href="https://stripe.com/docs/api/metadata">key-value pairs</a> that you can attach
     * to an object. This can be useful for storing additional information about the object in a
     * structured format. Individual keys can be unset by posting an empty value to them. All keys
     * can be unset by posting an empty value to {@code metadata}.
     */
    public Builder setMetadata(Map<String, String> metadata) {
      this.metadata = metadata;
      return this;
    }

    /** The meter tracking the usage of a metered price. */
    public Builder setMeter(String meter) {
      this.meter = meter;
      return this;
    }

    /** A brief description of the plan, hidden from customers. */
    public Builder setNickname(String nickname) {
      this.nickname = nickname;
      return this;
    }

    public Builder setProduct(PlanCreateParams.Product product) {
      this.product = product;
      return this;
    }

    public Builder setProduct(String product) {
      this.product = product;
      return this;
    }

    /**
     * Add an element to `tiers` list. A list is initialized for the first `add/addAll` call, and
     * subsequent calls adds additional elements to the original list. See {@link
     * PlanCreateParams#tiers} for the field documentation.
     */
    public Builder addTier(PlanCreateParams.Tier element) {
      if (this.tiers == null) {
        this.tiers = new ArrayList<>();
      }
      this.tiers.add(element);
      return this;
    }

    /**
     * Add all elements to `tiers` list. A list is initialized for the first `add/addAll` call, and
     * subsequent calls adds additional elements to the original list. See {@link
     * PlanCreateParams#tiers} for the field documentation.
     */
    public Builder addAllTier(List<PlanCreateParams.Tier> elements) {
      if (this.tiers == null) {
        this.tiers = new ArrayList<>();
      }
      this.tiers.addAll(elements);
      return this;
    }

    /**
     * Defines if the tiering price should be {@code graduated} or {@code volume} based. In {@code
     * volume}-based tiering, the maximum quantity within a period determines the per unit price, in
     * {@code graduated} tiering pricing can successively change as the quantity grows.
     */
    public Builder setTiersMode(PlanCreateParams.TiersMode tiersMode) {
      this.tiersMode = tiersMode;
      return this;
    }

    /**
     * Apply a transformation to the reported usage or set quantity before computing the billed
     * price. Cannot be combined with {@code tiers}.
     */
    public Builder setTransformUsage(PlanCreateParams.TransformUsage transformUsage) {
      this.transformUsage = transformUsage;
      return this;
    }

    /**
     * Default number of trial days when subscribing a customer to this plan using <a
     * href="https://stripe.com/docs/api#create_subscription-trial_from_plan">{@code
     * trial_from_plan=true}</a>.
     */
    public Builder setTrialPeriodDays(Long trialPeriodDays) {
      this.trialPeriodDays = trialPeriodDays;
      return this;
    }

    /**
     * Configures how the quantity per period should be determined. Can be either {@code metered} or
     * {@code licensed}. {@code licensed} automatically bills the {@code quantity} set when adding
     * it to a subscription. {@code metered} aggregates the total usage based on usage records.
     * Defaults to {@code licensed}.
     */
    public Builder setUsageType(PlanCreateParams.UsageType usageType) {
      this.usageType = usageType;
      return this;
    }
  }

  @Getter
  @EqualsAndHashCode(callSuper = false)
  public static class Product {
    /** Whether the product is currently available for purchase. Defaults to {@code true}. */
    @SerializedName("active")
    Boolean active;

    /**
     * Map of extra parameters for custom features not available in this client library. The content
     * in this map is not serialized under this field's {@code @SerializedName} value. Instead, each
     * key/value pair is serialized as if the key is a root-level field (serialized) name in this
     * param object. Effectively, this map is flattened to its parent instance.
     */
    @SerializedName(ApiRequestParams.EXTRA_PARAMS_KEY)
    Map<String, Object> extraParams;

    /**
     * The identifier for the product. Must be unique. If not provided, an identifier will be
     * randomly generated.
     */
    @SerializedName("id")
    String id;

    /**
     * Set of <a href="https://stripe.com/docs/api/metadata">key-value pairs</a> that you can attach
     * to an object. This can be useful for storing additional information about the object in a
     * structured format. Individual keys can be unset by posting an empty value to them. All keys
     * can be unset by posting an empty value to {@code metadata}.
     */
    @SerializedName("metadata")
    Map<String, String> metadata;

    /** <strong>Required.</strong> The product's name, meant to be displayable to the customer. */
    @SerializedName("name")
    String name;

    /**
     * An arbitrary string to be displayed on your customer's credit card or bank statement. While
     * most banks display this information consistently, some may display it incorrectly or not at
     * all.
     *
     * <p>This may be up to 22 characters. The statement description may not include {@code <},
     * {@code >}, {@code \}, {@code "}, {@code '} characters, and will appear on your customer's
     * statement in capital letters. Non-ASCII characters are automatically stripped.
     */
    @SerializedName("statement_descriptor")
    String statementDescriptor;

    /** A <a href="https://stripe.com/docs/tax/tax-categories">tax code</a> ID. */
    @SerializedName("tax_code")
    String taxCode;

    /**
     * A label that represents units of this product. When set, this will be included in customers'
     * receipts, invoices, Checkout, and the customer portal.
     */
    @SerializedName("unit_label")
    String unitLabel;

    private Product(
        Boolean active,
        Map<String, Object> extraParams,
        String id,
        Map<String, String> metadata,
        String name,
        String statementDescriptor,
        String taxCode,
        String unitLabel) {
      this.active = active;
      this.extraParams = extraParams;
      this.id = id;
      this.metadata = metadata;
      this.name = name;
      this.statementDescriptor = statementDescriptor;
      this.taxCode = taxCode;
      this.unitLabel = unitLabel;
    }

    public static Builder builder() {
      return new Builder();
    }

    public static class Builder {
      private Boolean active;

      private Map<String, Object> extraParams;

      private String id;

      private Map<String, String> metadata;

      private String name;

      private String statementDescriptor;

      private String taxCode;

      private String unitLabel;

      /** Finalize and obtain parameter instance from this builder. */
      public PlanCreateParams.Product build() {
        return new PlanCreateParams.Product(
            this.active,
            this.extraParams,
            this.id,
            this.metadata,
            this.name,
            this.statementDescriptor,
            this.taxCode,
            this.unitLabel);
      }

      /** Whether the product is currently available for purchase. Defaults to {@code true}. */
      public Builder setActive(Boolean active) {
        this.active = active;
        return this;
      }

      /**
       * Add a key/value pair to `extraParams` map. A map is initialized for the first `put/putAll`
       * call, and subsequent calls add additional key/value pairs to the original map. See {@link
       * PlanCreateParams.Product#extraParams} for the field documentation.
       */
      public Builder putExtraParam(String key, Object value) {
        if (this.extraParams == null) {
          this.extraParams = new HashMap<>();
        }
        this.extraParams.put(key, value);
        return this;
      }

      /**
       * Add all map key/value pairs to `extraParams` map. A map is initialized for the first
       * `put/putAll` call, and subsequent calls add additional key/value pairs to the original map.
       * See {@link PlanCreateParams.Product#extraParams} for the field documentation.
       */
      public Builder putAllExtraParam(Map<String, Object> map) {
        if (this.extraParams == null) {
          this.extraParams = new HashMap<>();
        }
        this.extraParams.putAll(map);
        return this;
      }

      /**
       * The identifier for the product. Must be unique. If not provided, an identifier will be
       * randomly generated.
       */
      public Builder setId(String id) {
        this.id = id;
        return this;
      }

      /**
       * Add a key/value pair to `metadata` map. A map is initialized for the first `put/putAll`
       * call, and subsequent calls add additional key/value pairs to the original map. See {@link
       * PlanCreateParams.Product#metadata} for the field documentation.
       */
      public Builder putMetadata(String key, String value) {
        if (this.metadata == null) {
          this.metadata = new HashMap<>();
        }
        this.metadata.put(key, value);
        return this;
      }

      /**
       * Add all map key/value pairs to `metadata` map. A map is initialized for the first
       * `put/putAll` call, and subsequent calls add additional key/value pairs to the original map.
       * See {@link PlanCreateParams.Product#metadata} for the field documentation.
       */
      public Builder putAllMetadata(Map<String, String> map) {
        if (this.metadata == null) {
          this.metadata = new HashMap<>();
        }
        this.metadata.putAll(map);
        return this;
      }

      /** <strong>Required.</strong> The product's name, meant to be displayable to the customer. */
      public Builder setName(String name) {
        this.name = name;
        return this;
      }

      /**
       * An arbitrary string to be displayed on your customer's credit card or bank statement. While
       * most banks display this information consistently, some may display it incorrectly or not at
       * all.
       *
       * <p>This may be up to 22 characters. The statement description may not include {@code <},
       * {@code >}, {@code \}, {@code "}, {@code '} characters, and will appear on your customer's
       * statement in capital letters. Non-ASCII characters are automatically stripped.
       */
      public Builder setStatementDescriptor(String statementDescriptor) {
        this.statementDescriptor = statementDescriptor;
        return this;
      }

      /** A <a href="https://stripe.com/docs/tax/tax-categories">tax code</a> ID. */
      public Builder setTaxCode(String taxCode) {
        this.taxCode = taxCode;
        return this;
      }

      /**
       * A label that represents units of this product. When set, this will be included in
       * customers' receipts, invoices, Checkout, and the customer portal.
       */
      public Builder setUnitLabel(String unitLabel) {
        this.unitLabel = unitLabel;
        return this;
      }
    }
  }

  @Getter
  @EqualsAndHashCode(callSuper = false)
  public static class Tier {
    /**
     * Map of extra parameters for custom features not available in this client library. The content
     * in this map is not serialized under this field's {@code @SerializedName} value. Instead, each
     * key/value pair is serialized as if the key is a root-level field (serialized) name in this
     * param object. Effectively, this map is flattened to its parent instance.
     */
    @SerializedName(ApiRequestParams.EXTRA_PARAMS_KEY)
    Map<String, Object> extraParams;

    /**
     * The flat billing amount for an entire tier, regardless of the number of units in the tier.
     */
    @SerializedName("flat_amount")
    Long flatAmount;

    /**
     * Same as {@code flat_amount}, but accepts a decimal value representing an integer in the minor
     * units of the currency. Only one of {@code flat_amount} and {@code flat_amount_decimal} can be
     * set.
     */
    @SerializedName("flat_amount_decimal")
    BigDecimal flatAmountDecimal;

    /** The per unit billing amount for each individual unit for which this tier applies. */
    @SerializedName("unit_amount")
    Long unitAmount;

    /**
     * Same as {@code unit_amount}, but accepts a decimal value in cents (or local equivalent) with
     * at most 12 decimal places. Only one of {@code unit_amount} and {@code unit_amount_decimal}
     * can be set.
     */
    @SerializedName("unit_amount_decimal")
    BigDecimal unitAmountDecimal;

    /**
     * <strong>Required.</strong> Specifies the upper bound of this tier. The lower bound of a tier
     * is the upper bound of the previous tier adding one. Use {@code inf} to define a fallback
     * tier.
     */
    @SerializedName("up_to")
    Object upTo;

    private Tier(
        Map<String, Object> extraParams,
        Long flatAmount,
        BigDecimal flatAmountDecimal,
        Long unitAmount,
        BigDecimal unitAmountDecimal,
        Object upTo) {
      this.extraParams = extraParams;
      this.flatAmount = flatAmount;
      this.flatAmountDecimal = flatAmountDecimal;
      this.unitAmount = unitAmount;
      this.unitAmountDecimal = unitAmountDecimal;
      this.upTo = upTo;
    }

    public static Builder builder() {
      return new Builder();
    }

    public static class Builder {
      private Map<String, Object> extraParams;

      private Long flatAmount;

      private BigDecimal flatAmountDecimal;

      private Long unitAmount;

      private BigDecimal unitAmountDecimal;

      private Object upTo;

      /** Finalize and obtain parameter instance from this builder. */
      public PlanCreateParams.Tier build() {
        return new PlanCreateParams.Tier(
            this.extraParams,
            this.flatAmount,
            this.flatAmountDecimal,
            this.unitAmount,
            this.unitAmountDecimal,
            this.upTo);
      }

      /**
       * Add a key/value pair to `extraParams` map. A map is initialized for the first `put/putAll`
       * call, and subsequent calls add additional key/value pairs to the original map. See {@link
       * PlanCreateParams.Tier#extraParams} for the field documentation.
       */
      public Builder putExtraParam(String key, Object value) {
        if (this.extraParams == null) {
          this.extraParams = new HashMap<>();
        }
        this.extraParams.put(key, value);
        return this;
      }

      /**
       * Add all map key/value pairs to `extraParams` map. A map is initialized for the first
       * `put/putAll` call, and subsequent calls add additional key/value pairs to the original map.
       * See {@link PlanCreateParams.Tier#extraParams} for the field documentation.
       */
      public Builder putAllExtraParam(Map<String, Object> map) {
        if (this.extraParams == null) {
          this.extraParams = new HashMap<>();
        }
        this.extraParams.putAll(map);
        return this;
      }

      /**
       * The flat billing amount for an entire tier, regardless of the number of units in the tier.
       */
      public Builder setFlatAmount(Long flatAmount) {
        this.flatAmount = flatAmount;
        return this;
      }

      /**
       * Same as {@code flat_amount}, but accepts a decimal value representing an integer in the
       * minor units of the currency. Only one of {@code flat_amount} and {@code
       * flat_amount_decimal} can be set.
       */
      public Builder setFlatAmountDecimal(BigDecimal flatAmountDecimal) {
        this.flatAmountDecimal = flatAmountDecimal;
        return this;
      }

      /** The per unit billing amount for each individual unit for which this tier applies. */
      public Builder setUnitAmount(Long unitAmount) {
        this.unitAmount = unitAmount;
        return this;
      }

      /**
       * Same as {@code unit_amount}, but accepts a decimal value in cents (or local equivalent)
       * with at most 12 decimal places. Only one of {@code unit_amount} and {@code
       * unit_amount_decimal} can be set.
       */
      public Builder setUnitAmountDecimal(BigDecimal unitAmountDecimal) {
        this.unitAmountDecimal = unitAmountDecimal;
        return this;
      }

      /**
       * <strong>Required.</strong> Specifies the upper bound of this tier. The lower bound of a
       * tier is the upper bound of the previous tier adding one. Use {@code inf} to define a
       * fallback tier.
       */
      public Builder setUpTo(PlanCreateParams.Tier.UpTo upTo) {
        this.upTo = upTo;
        return this;
      }

      /**
       * <strong>Required.</strong> Specifies the upper bound of this tier. The lower bound of a
       * tier is the upper bound of the previous tier adding one. Use {@code inf} to define a
       * fallback tier.
       */
      public Builder setUpTo(Long upTo) {
        this.upTo = upTo;
        return this;
      }
    }

    public enum UpTo implements ApiRequestParams.EnumParam {
      @SerializedName("inf")
      INF("inf");

      @Getter(onMethod_ = {@Override})
      private final String value;

      UpTo(String value) {
        this.value = value;
      }
    }
  }

  @Getter
  @EqualsAndHashCode(callSuper = false)
  public static class TransformUsage {
    /** <strong>Required.</strong> Divide usage by this number. */
    @SerializedName("divide_by")
    Long divideBy;

    /**
     * Map of extra parameters for custom features not available in this client library. The content
     * in this map is not serialized under this field's {@code @SerializedName} value. Instead, each
     * key/value pair is serialized as if the key is a root-level field (serialized) name in this
     * param object. Effectively, this map is flattened to its parent instance.
     */
    @SerializedName(ApiRequestParams.EXTRA_PARAMS_KEY)
    Map<String, Object> extraParams;

    /**
     * <strong>Required.</strong> After division, either round the result {@code up} or {@code
     * down}.
     */
    @SerializedName("round")
    Round round;

    private TransformUsage(Long divideBy, Map<String, Object> extraParams, Round round) {
      this.divideBy = divideBy;
      this.extraParams = extraParams;
      this.round = round;
    }

    public static Builder builder() {
      return new Builder();
    }

    public static class Builder {
      private Long divideBy;

      private Map<String, Object> extraParams;

      private Round round;

      /** Finalize and obtain parameter instance from this builder. */
      public PlanCreateParams.TransformUsage build() {
        return new PlanCreateParams.TransformUsage(this.divideBy, this.extraParams, this.round);
      }

      /** <strong>Required.</strong> Divide usage by this number. */
      public Builder setDivideBy(Long divideBy) {
        this.divideBy = divideBy;
        return this;
      }

      /**
       * Add a key/value pair to `extraParams` map. A map is initialized for the first `put/putAll`
       * call, and subsequent calls add additional key/value pairs to the original map. See {@link
       * PlanCreateParams.TransformUsage#extraParams} for the field documentation.
       */
      public Builder putExtraParam(String key, Object value) {
        if (this.extraParams == null) {
          this.extraParams = new HashMap<>();
        }
        this.extraParams.put(key, value);
        return this;
      }

      /**
       * Add all map key/value pairs to `extraParams` map. A map is initialized for the first
       * `put/putAll` call, and subsequent calls add additional key/value pairs to the original map.
       * See {@link PlanCreateParams.TransformUsage#extraParams} for the field documentation.
       */
      public Builder putAllExtraParam(Map<String, Object> map) {
        if (this.extraParams == null) {
          this.extraParams = new HashMap<>();
        }
        this.extraParams.putAll(map);
        return this;
      }

      /**
       * <strong>Required.</strong> After division, either round the result {@code up} or {@code
       * down}.
       */
      public Builder setRound(PlanCreateParams.TransformUsage.Round round) {
        this.round = round;
        return this;
      }
    }

    public enum Round implements ApiRequestParams.EnumParam {
      @SerializedName("down")
      DOWN("down"),

      @SerializedName("up")
      UP("up");

      @Getter(onMethod_ = {@Override})
      private final String value;

      Round(String value) {
        this.value = value;
      }
    }
  }

  public enum BillingScheme implements ApiRequestParams.EnumParam {
    @SerializedName("per_unit")
    PER_UNIT("per_unit"),

    @SerializedName("tiered")
    TIERED("tiered");

    @Getter(onMethod_ = {@Override})
    private final String value;

    BillingScheme(String value) {
      this.value = value;
    }
  }

  public enum Interval implements ApiRequestParams.EnumParam {
    @SerializedName("day")
    DAY("day"),

    @SerializedName("month")
    MONTH("month"),

    @SerializedName("week")
    WEEK("week"),

    @SerializedName("year")
    YEAR("year");

    @Getter(onMethod_ = {@Override})
    private final String value;

    Interval(String value) {
      this.value = value;
    }
  }

  public enum TiersMode implements ApiRequestParams.EnumParam {
    @SerializedName("graduated")
    GRADUATED("graduated"),

    @SerializedName("volume")
    VOLUME("volume");

    @Getter(onMethod_ = {@Override})
    private final String value;

    TiersMode(String value) {
      this.value = value;
    }
  }

  public enum UsageType implements ApiRequestParams.EnumParam {
    @SerializedName("licensed")
    LICENSED("licensed"),

    @SerializedName("metered")
    METERED("metered");

    @Getter(onMethod_ = {@Override})
    private final String value;

    UsageType(String value) {
      this.value = value;
    }
  }
}
